package owg.util.opengl.models;

import com.jogamp.opengl.*;

import owg.util.opengl.EGL;



/**
 * This object can be used to build and store Display Lists.
 * Is an implementation of High Performance Renderable.
 * 
 * Note that display lists are completely static and need to be recreated from scratch when anything changes.
 * This includes changing the render limit, index buffer or vertex buffer. The process of building a display
 * list is expensive, so it should only be used for geometry that does not change.
 */
public class DLS extends HPRS
{
	/**Pointers to the display list*/
	int list = 0;
	
	private boolean listOutdated;
	
	/**Construct a new object which uses the vertex data from dataSrc
	 * Index data must be specified.*/
	public DLS(DLS dataSrc, int faceMode, String name)
	{
		super(name, faceMode, dataSrc.numVertexComponents, dataSrc.useNormal, dataSrc.numColorComponents, dataSrc.numTexCoordComponents, dataSrc.numTexCoordComponents2);
		
		setPrepackedVData(dataSrc.vData);
		setPrepackedIData(dataSrc.iData);
		//Note: Display list does not support shared lists because this is completely useless.
		listOutdated=false;
	}
	/**Construct an empty object with the given settings*/
	public DLS(String name, int faceMode, int nVertexComps, boolean useNormal, int nColorComps, 
		int nTexCoords, int nTexCoords2)
		{
		super(name, faceMode, (byte)nVertexComps, useNormal, (byte)nColorComps, (byte)nTexCoords, (byte)nTexCoords2);
		}
	/**Construct an empty object with the given settings*/
	public DLS(int faceMode, boolean useNormal, boolean useColor, boolean useAlpha, 
		boolean useTexCoord,boolean use3DTexCoord, boolean useTexCoord2, boolean use3DTexCoord2, String name)
		{
		this(name, faceMode, 3, useNormal, (useColor?(useAlpha?4:3):0), (useTexCoord?(use3DTexCoord?3:2):0), (useTexCoord2?(use3DTexCoord2?3:2):0));
		}
	@Override
	public void requestVUpdate()
	{
		listOutdated = true;
	}
	@Override
	public void requestIUpdate()
	{
		//Element indexing not supported by display lists...
		listOutdated = true;
	}
	
	@Override
	protected void endImpl()
	{
		//Display list needs to be completely recreated even for the slightest change.
		genList();
	}
	
	private void genList()
	{
		GL2 gl = (GL2) egl.getGL();
		if(list!=0)
			gl.glDeleteLists(list, 1);
		list = gl.glGenLists(1);
		gl.glNewList( list, GL2.GL_COMPILE );
		
		int end = 0;
		for(int i=0; i<faceModeEndIndices.size(); i++)
		{
			int currentFaceMode = faceModes.get(i);
			int start = end;
			end = faceModeEndIndices.get(i);
			if(renderLimit != -1) 
			{
				if(start >= renderLimit)
					break;
				end = Math.min(end, renderLimit);
			}
			gl.glBegin(currentFaceMode);
			
			for(int j=start; j<end; j++)
			{
				int k = iData[j];
				
				if(useNormal)
					gl.glNormal3sv(vData, (vertexStride*k+normalPointer));
				if(numColorComponents > 0)
				{
					if(numColorComponents > 3)
						gl.glColor4usv(vData, (vertexStride*k+colorPointer));
					else
						gl.glColor3usv(vData, (vertexStride*k+colorPointer));
				}
				if(numTexCoordComponents > 0)
				{
					if(numTexCoordComponents > 3)
						gl.glTexCoord4sv(vData, (vertexStride*k+texCoordPointer));
					if(numTexCoordComponents == 3)
						gl.glTexCoord3sv(vData, (vertexStride*k+texCoordPointer));
					else if(numTexCoordComponents == 2)
						gl.glTexCoord2sv(vData, (vertexStride*k+texCoordPointer));
					else 
						gl.glTexCoord1sv(vData, (vertexStride*k+texCoordPointer));
				}
				if(numTexCoordComponents2 > 0)
				{
					if(numTexCoordComponents2 > 3)
						gl.glMultiTexCoord4sv(GL2.GL_TEXTURE1, vData, (vertexStride*k+texCoordPointer2));
					if(numTexCoordComponents2 == 3)
						gl.glMultiTexCoord3sv(GL2.GL_TEXTURE1, vData, (vertexStride*k+texCoordPointer2));
					else if(numTexCoordComponents2 == 2)
						gl.glMultiTexCoord2sv(GL2.GL_TEXTURE1, vData, (vertexStride*k+texCoordPointer2));
					else 
						gl.glMultiTexCoord1sv(GL2.GL_TEXTURE1, vData, (vertexStride*k+texCoordPointer2));
				}
				if(numVertexComponents > 3)
					gl.glVertex4sv(vData, (vertexStride*k+vertexPointer));
				else if(numVertexComponents == 3)
					gl.glVertex3sv(vData, (vertexStride*k+vertexPointer));
				else 
					gl.glVertex2sv(vData, (vertexStride*k+vertexPointer));
			}
			
			gl.glEnd();
		}
		gl.glEndList();
		listOutdated = false;
	}
	
	/* (non-Javadoc)
	 * @see graphics.HPR#render()
	 */
	@Override
	public void render() 
	{
		GL2 gl = (GL2) egl.getGL();
		
		
		if(listOutdated)
			genList();
		gl.glCallList(list);
	}

	@Override
	public void dispose(EGL<?> egl) 
	{
		if(list != -1)
		{
			((GL2)egl.getGL()).glDeleteLists(list, 1);
			list = -1;
		}
	}
	
	
	@Override
	public void finalize()
	{
		//GC runs in a different thread, so accessing the GL here is unsafe.
		if(list != -1)
			egl.invokeLater(new Runnable()
			{
				@Override
				public void run()
				{
					assert ((GL2)egl.getGL()).glIsList(list) : this+" was disposed with an invalid list!";
					((GL2)egl.getGL()).glDeleteLists(list, 1);
				}
			});
	}
}
